/**
 *
 */
package com.newer.utils;

import com.newer.biz.sys.auth.ShiroBiz;
import com.newer.biz.sys.menu.MenuInfoBiz;
import com.newer.commons.constants.CommonConstants;
import com.newer.commons.result.BizResult;
import com.newer.config.shiro.realms.ShiroAuthcRealm;
import com.newer.dao.bean.sys.Menu;
import com.newer.dao.bean.sys.MenuPermission;
import com.newer.dao.bean.sys.User;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 权限相关工具
 *
 * @author xuntj
 * @create 2018-04-08 13:51
 **/
public class ShiroAuthUtils {

    /**
     * 清除登录缓存
     *
     * @param subject
     */
    public static void clearUserAuth(Subject subject, Object principal) {
        // 刷新主体
        RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        ShiroAuthcRealm shiroRealm = (ShiroAuthcRealm) rsm.getRealms().iterator().next();
        String realmName = subject.getPrincipals().getRealmNames().iterator().next();
        //第一个参数为用户名,第二个参数为realmName,test想要操作权限的用户
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, realmName);
        subject.runAs(principals);
        shiroRealm.clearAuthz();
    }

    /**
     * 清除所有认证缓存
     */
    public static void clearAllAuth() {
        // 刷新主体
        RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        ShiroAuthcRealm shiroRealm = (ShiroAuthcRealm) rsm.getRealms().iterator().next();
        shiroRealm.clearAllCachedAuthorizationInfo();
    }

    /**
     * 获取当前登录用户
     *
     * @param subject
     */
    public static User getAuthUser(Subject subject) {
        return (User) subject.getPrincipal();
    }


    /**
     * 设置菜访问权限
     *
     * @param shiroBiz
     * @param filterChainDefinitionMap
     */
    public static Map<String, String> menuAuth(MenuInfoBiz menuInfoBiz, ShiroBiz shiroBiz, Map<String, String> filterChainDefinitionMap) {
        // 查询菜单信息
        BizResult<Menu> menuResult = menuInfoBiz.queryAllMenus(CommonConstants.IS_MENU);
        // 判断查询结果是否成功
        if (menuResult.isSuccess() && CollectionUtils.isNotEmpty(menuResult.getResults())) {
            // 获取所有菜单集合
            List<Menu> menuInfos = menuResult.getResults();
            // 循环菜单集合,获取菜单访问权限
            for (Menu menuInfo : menuInfos) {
                // 根据菜单ID查询菜单的权限信息
                BizResult<MenuPermission> menuPermsInfoResult = shiroBiz
                        .findMenuPermsByMenuId(menuInfo.getId());
                // 判断结果是否成功
                if (menuPermsInfoResult.isSuccess()
                        && CollectionUtils.isNotEmpty(menuPermsInfoResult.getResults())) {
                    // 获取菜单访问权限集合
                    List<MenuPermission> menuPermsInfos = menuPermsInfoResult.getResults();
                    // 定义权限关系
                    Boolean anyPerms = false;
                    // 定义菜单访问权限
                    String permsCodes = StringUtils.EMPTY;
                    // 循环集合
                    for (MenuPermission menuPermsInfo : menuPermsInfos) {
                        // 判断权限是否已经存在
                        if (StringUtils.isNotBlank(permsCodes)) {
                            permsCodes += "," + menuPermsInfo.getPermissionCode();
                        } else {
                            permsCodes += menuPermsInfo.getPermissionCode();
                        }
                        // 判断关系
                        // 1:且的关系;2:或的关系
                        if (menuPermsInfo.getRelType().equals(2)) {
                            anyPerms = true;
                        }
                    }
                    // 封装权限信息
                    String menuAuths = StringUtils.EMPTY;
                    // 判断权限Code是否为空
                    if (StringUtils.isNotBlank(permsCodes)) {
                        menuAuths += "authc,";
                        // 判断权限关系类型
                        if (anyPerms) {
                            // 拼接权限关系
                            menuAuths += "anyPerms[" + permsCodes + "]";
                        } else {
                            // 拼接角色关系
                            menuAuths += "perms[" + permsCodes + "]";
                        }
                    }
                    // 设置菜单访问权限
                    filterChainDefinitionMap.put(menuInfo.getMenuUrl(), menuAuths);
                }
            }
        }
        // 返回结果
        return filterChainDefinitionMap;
    }


    /**
     * 重新加载权限
     */
    public static void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, MenuInfoBiz menuInfoBiz, ShiroBiz shiroBiz) {

        synchronized (shiroFilterFactoryBean) {

            AbstractShiroFilter shiroFilter = null;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean
                        .getObject();
            } catch (Exception e) {
                throw new RuntimeException(
                        "get ShiroFilter from shiroFilterFactoryBean error!");
            }

            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
                    .getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
                    .getFilterChainManager();

            // 清空老的权限控制
            manager.getFilterChains().clear();

            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();

            // 拦截器.
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();

            // 添加默认信息配置
            // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
            filterChainDefinitionMap.put("/logout.do", "logout");
            // 防止登录成功之后下载favicon.ico
            filterChainDefinitionMap.put("/favicon.ico", "anon");
            filterChainDefinitionMap.put("/login.do", "anon");

            // 如果不设置默认会自动寻找Web工程根目录下的"/login.ftl"页面
            shiroFilterFactoryBean.setLoginUrl("/login.htm");
            // 登录成功后要跳转的链接
            shiroFilterFactoryBean.setSuccessUrl("/index.htm");
            // 未授权界面;
            shiroFilterFactoryBean.setUnauthorizedUrl("/403.htm");

            shiroFilterFactoryBean
                    .setFilterChainDefinitionMap(menuAuth(menuInfoBiz, shiroBiz, filterChainDefinitionMap));
            // 重新构建生成
            Map<String, String> chains = shiroFilterFactoryBean
                    .getFilterChainDefinitionMap();
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim()
                        .replace(" ", "");
                manager.createChain(url, chainDefinition);
            }
        }
    }
}
